#include <stdio.h>
#include <SDL2/SDL.h>
#include <libavformat/avformat.h>
#include <libavcodec/codec.h>
#include <libswresample/swresample.h>

AVFormatContext * myavformat=NULL; //申请的上下文结构体
AVCodec *myavcode = NULL;            //查找到的解码器
DECLSPEC SDL_AudioDeviceID myaudio_id;
SDL_AudioSpec des,obt;               //obt实际得到的音频的格式
AVPacket *mypkt=NULL;    
AVFrame *myframe = NULL;
struct SwsContext *mysws=NULL;

/*
 * 主函数：实现音频文件的解码和播放
 * 使用FFmpeg进行音频解码，使用SDL进行音频播放
 * 包含初始化、解码、重采样、播放等步骤
 */
int main()
{
	//1.初始化ffmpeg所支持的所有协议
	void av_register_all();
	//2.申请上下文结构体
	myavformat = avformat_alloc_context();
	//3.打开音频文件
	avformat_open_input(&myavformat,"/home/lx/tools/2.mp4",NULL,NULL);
	//4.查看文件流媒体信息
	avformat_find_stream_info(myavformat, NULL);
	//5.查找解码器
	myavcode = avcodec_find_decoder(myavformat->streams[1]->codecpar->codec_id);
	//6.初始化解码器
	avcodec_open2(myavformat->streams[1]->codec , myavcode, NULL);
	//7.初始化音频设备
	SDL_Init(SDL_INIT_AUDIO);
	//8.打开音频设备
	des.channels = myavformat->streams[1]->codecpar->channels; //声道
	des.format = AUDIO_F32SYS;//位宽
	des.silence = 0;          //静音
	des.samples = 1024;      //缓冲器
	des.size = 0;
	des.freq = myavformat->streams[1]->codecpar->sample_rate;  //采样率
	myaudio_id = SDL_OpenAudioDevice(NULL,0,&des,&obt,0);      

	enum AVSampleFormat myavfmt={0};

	switch(obt.format)    //
	{
		case AUDIO_F32SYS: 
				myavfmt = AV_SAMPLE_FMT_FLT;
				break;
		case AUDIO_S32SYS:
				myavfmt = AV_SAMPLE_FMT_S32;
				break;
		case AUDIO_S16SYS:
				myavfmt = AV_SAMPLE_FMT_S16;
				break;
	}

	//设置音频重采样的上下文结构体
	mysws = swr_alloc_set_opts(NULL,av_get_default_channel_layout(obt.channels),\
	myavfmt,obt.freq,av_get_default_channel_layout(myavformat->streams[1]->codecpar->channels),\
	myavformat->streams[1]->codec->sample_fmt,myavformat->streams[1]->codec->sample_rate,0,NULL);

	//初始化音频重采样的上下文结构体
	swr_init(mysws);

	//9.启动音频设备
	SDL_PauseAudioDevice(myaudio_id,0);

	// 分配一个AVPacket结构体，用于存储从文件中读取的压缩数据包
	mypkt = av_packet_alloc();
	// 分配一个AVFrame结构体，用于存储解码后的原始音频数据
	myframe = av_frame_alloc();
	// 循环读取文件中的数据包，直到文件结束（返回非0值）
	while(av_read_frame(myavformat,mypkt)==0)
	{
		if(mypkt->stream_index == 1) // 检查当前数据包是否属于音频流（stream_index == 1）
		{
			avcodec_send_packet(myavformat->streams[1]->codec,mypkt);       // 将压缩的音频数据包发送到解码器
			avcodec_receive_frame(myavformat->streams[1]->codec,myframe);  // 接收解码后的原始音频数据

			if(myframe->sample_rate == 0)  // 检查帧的采样率是否为0，如果是则跳过当前帧（无效帧）
			{
				continue;
			}
			int count=obt.freq*myframe->nb_samples/myframe->sample_rate; // 计算重采样后的样本数量
			int bufcount=av_samples_get_buffer_size(NULL,obt.channels,count,myavfmt,0);// 计算重采样后所需的缓冲区大小
			uint8_t *out =av_malloc(bufcount);        // 为输出缓冲区分配内存
			//音频重采样
			swr_convert(mysws,&out,bufcount,myframe->extended_data,myframe->nb_samples);
			//播放音频
			SDL_QueueAudio(myaudio_id,out,bufcount);
			//延时
			SDL_Delay((bufcount*1000)/(obt.freq*av_get_bytes_per_sample(myavfmt)*(obt.channels)-1));
		}
	}
	return 0;
	
}

